package com.wahoyu.exportwordtest.service;

import com.wahoyu.exportwordtest.utils.SvgToPngConverter;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

/**
 * @Author wanghongyu02
 * @Date 2025/4/18 14:56
 */
@Slf4j
@Service
public class EchartsService {

    // word文件夹路径
    @Value("${wordPath:/pathError}")
    private String wordPath;

    // word文件夹路径
    @Value("${nodePath:/nodePathError}")
    private String nodePath;

    private String OUTPUT_FILE_PATH;
    private String PNG_PATH;
    private String JS_PATH;
    private String OPTIONS_PATH;

    @PostConstruct
    public void initPaths() {
        this.OUTPUT_FILE_PATH = wordPath + "word/echarts/tmp.svg";
        this.PNG_PATH = wordPath + "word/echarts/tmp.png";
        this.JS_PATH = wordPath + "word/echarts/genSVG.js";
        this.OPTIONS_PATH = wordPath + "word/echarts";
    }

    /**
     * 生成Echarts图片并以字节数组的方式进行返回
     * @author wanghongyu02
     * @Date 2025/4/21 09:27
     */
    public byte[] getEchartsImgBytes(Map<String, Object> templateMap, String optionFileName) throws TemplateException, IOException {

        // 将templateMap中的变量替换到option.ftl文件中
        String option = this.generateString(optionFileName, templateMap);

        // 替换option中的换行和空格
        option = option.replaceAll("\\n", "")
                .replaceAll("\\s", "");
        option = option.replace('"', '\'');

        log.info("add by why02 替换后的option--- {}", option);

        // 发送node命令，将图片生成到本地路径：OUTPUT_FILE_PATH
        int result = this.generatePngToLocal(option);
        if (result != 1) {
            throw new RuntimeException("生成图片失败");
        }
        log.info("图片生成成功！");

        // 拿到本地图片，将本地图片转化为byte数组进行返回，并删除本地文件
        byte[] imgByteData = this.getImgByte();

        // 对字节数组进行校验
        if (imgByteData.length <= 1) {
            throw new RuntimeException("图片转化失败!");
        }
        // log.info("getEchartsImgBytes-imgByteData: {}", Arrays.toString(imgByteData));

        return imgByteData;
    }


    /**
     * 将图片转化为byte数组进行返回，并删除本地文件
     * @return
     * @author wanghongyu02
     * @Date 2025/4/18 15:46
     */
    public byte[] getImgByte() {

        byte[] imageByteData = new byte[0];

        try {
            // 读取图片文件为字节数组
            File svg = new File(OUTPUT_FILE_PATH);
            File png = new File(PNG_PATH);
            try {
                SvgToPngConverter.convertSvgToPng(svg, png);
            } catch (Exception ignored) {
                log.info("图片转化错误");
            }
            imageByteData = Files.readAllBytes(Paths.get(PNG_PATH));
            Files.delete(Paths.get(OUTPUT_FILE_PATH));
            Files.delete(Paths.get(PNG_PATH));
            log.info("本地文件已成功删除");

        } catch (IOException e) {
            log.info("图片转化错误");
            e.printStackTrace();

            // 检查文件是否存在（可能在删除前已被移除）
            if (Files.exists(Paths.get(OUTPUT_FILE_PATH)) || Files.exists(Paths.get(PNG_PATH))) {
                log.info("警告：原始文件仍然存在");
            }
        }
        return imageByteData;
    }

    /**
     * 调用js文件，生成临时折线图到本地OUTPUT_PATH目录
     * @param option
     * @author wanghongyu02
     * @Date 2025/4/18 15:30
     */
    private int generatePngToLocal(String option) {

        try {

            // 构建命令
            ProcessBuilder pb = new ProcessBuilder(nodePath, JS_PATH, OUTPUT_FILE_PATH);
//            ProcessBuilder pb = new ProcessBuilder(nodePath, JS_PATH, OUTPUT_FILE_PATH, ECHARTS_PATH);
            log.info("命令: {}", pb.command());
            Process process = pb.start();

            // 发送 option 到标准输入
            try (OutputStream os = process.getOutputStream()) {
                os.write(option.getBytes(StandardCharsets.UTF_8));
                os.flush();
            }

            // 等待完成
            int exitCode = process.waitFor();
            log.info("退出码: {}", exitCode);

            // 成功
            if (exitCode == 1) {
                return 1;
            }

            // 失败
            else if (exitCode == 2) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        log.info("[Node错误] {}", line);
                    }
                } catch (Exception e) {
                    log.error("[Node错误]", e);
                }
            }
        } catch (Exception e) {
            log.error("[Node错误]", e);
            return 2;
        }
        return 2;
    }

    /**
     * 拿到本地的option文件，并替换其中的变量
     * @author wanghongyu02
     * @Date 2025/4/21 09:26
     */
    public String generateString(String templateFileName, Map<String, Object> datas)
            throws IOException, TemplateException {

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);

        // 设置默认编码
        configuration.setDefaultEncoding("UTF-8");

        // 拿到option文件的上级文件夹
        File templatePath = new File(OPTIONS_PATH);
        configuration.setDirectoryForTemplateLoading(templatePath);

        // 拿到option.ftl文件，生成ftl模板对象
        Template template = configuration.getTemplate(templateFileName);

        // 将datas写入模板并返回
        try (StringWriter stringWriter = new StringWriter()) {
            template.process(datas, stringWriter);
            stringWriter.flush();
            return stringWriter.getBuffer().toString();
        }
    }
}